package com.liy.framework.common.orm.mybatis.interceptor;

import com.liy.framework.common.orm.dialect.Dialect;
import com.liy.framework.common.orm.dialect.DialectFactory;
import com.liy.framework.common.vo.PageVO;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Intercepts({@Signature(
        type = StatementHandler.class,
        method = "prepare",
        args = {Connection.class, Integer.class}
)})
public class PaginationStatementHandlerInterceptor implements Interceptor {

    private static final Logger logger = LoggerFactory.getLogger(PaginationStatementHandlerInterceptor.class);
    private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();


    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
        ParameterHandler parameterHandler = statementHandler.getParameterHandler();
        BoundSql boundSql = statementHandler.getBoundSql();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
        RowBounds rowBounds = (RowBounds)metaStatementHandler.getValue("delegate.rowBounds");
        if (rowBounds != null && rowBounds != RowBounds.DEFAULT) {
            Configuration configuration = (Configuration)metaStatementHandler.getValue("delegate.configuration");
            Dialect dialect = DialectFactory.buildDialect(configuration);
            String originalSql = (String)metaStatementHandler.getValue("delegate.boundSql.sql");
            PageVO<?> page = (PageVO)rowBounds;
            String countSql = dialect.getQueryCountString(originalSql);
            Connection connection = (Connection)invocation.getArgs()[0];
            int total = this.getTotal(parameterHandler, connection, countSql);
            page.setTotalCount(total);
            metaStatementHandler.setValue("delegate.boundSql.sql", dialect.getQueryDataString(originalSql, page.getOffset(), page.getLimit()));
            metaStatementHandler.setValue("delegate.rowBounds.offset", 0);
            metaStatementHandler.setValue("delegate.rowBounds.limit", 2147483647);
            if (logger.isDebugEnabled()) {
                logger.debug("分页SQL : " + boundSql.getSql());
            }

            return invocation.proceed();
        } else {
            return invocation.proceed();
        }
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {
    }

    private int getTotal(ParameterHandler parameterHandler, Connection connection, String countSql) throws Exception {
        PreparedStatement prepareStatement = null;
        ResultSet rs = null;
        int count = 0;

        try {
            prepareStatement = connection.prepareStatement(countSql);
            parameterHandler.setParameters(prepareStatement);
            rs = prepareStatement.executeQuery();
            if (rs.next()) {
                count = rs.getInt(1);
            }
        } catch (Exception var16) {
            var16.printStackTrace();
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }

                if (prepareStatement != null) {
                    prepareStatement.close();
                }
            } catch (SQLException var15) {
                var15.printStackTrace();
            }

        }

        return count;
    }
}
